package com.oig.sys.feign;


import com.oig.common.constants.CommonConstants;
import com.oig.sys.feign.config.FeignProperties;
import com.oig.sys.feign.decode.BadRequestDecoder;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.codec.ErrorDecoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 怎么才能自动扫描 api里的@FeignClient？
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(FeignProperties.class)
public class FeignConfiguration implements RequestInterceptor {


    //改为在配置文件里配置好点
//    @Bean
//    Logger.Level feignLogger(){
//        return Logger.Level.FULL;
//    }

    private final FeignProperties feignProperties;

    public FeignConfiguration(FeignProperties feignProperties) {
        this.feignProperties = feignProperties;
    }

    @Bean
    public ErrorDecoder errorDecoder(){
        return new BadRequestDecoder();
    }


    @Override
    public void apply(RequestTemplate template) {
        HttpServletRequest request = getHttpServletRequest();
        if (Objects.isNull(request)) {
            return;
        }
        String feignName = template.feignTarget().name();
        if (feignProperties.getIgnoreHeadCopyClients().contains(feignName)){
            this.addTraceId(template);
            return;
        }
        Map<String, String> headers = getHeaders(request);
        if (headers.size() > 0) {
            for (Map.Entry<String, String> entry : headers.entrySet()){
                template.header(entry.getKey(), entry.getValue());
            }
        }
        this.addTraceId(template);
    }

    private HttpServletRequest getHttpServletRequest() {
        try {
//            ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//            RequestContextHolder.setRequestAttributes(sra, true);
            
            return ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        } catch (Exception e) {
            return null;
        }
    }

    private Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration<String> enums = request.getHeaderNames();
        while (enums.hasMoreElements()) {
            String key = enums.nextElement();
            String value = request.getHeader(key);
            // 跳过 content 和 accept
            if (key.equalsIgnoreCase("content-length")){
                continue;
            }
            if (key.equalsIgnoreCase("content-type")){
                continue;
            }
            if (key.equalsIgnoreCase("accept")){
                continue;
            }
            if (key.equalsIgnoreCase("accept-encoding")){
                continue;
            }
            if (key.equalsIgnoreCase("accept-language")){
                continue;
            }
            map.put(key, value);
        }
        return map;
    }

    private void addTraceId(RequestTemplate template){
        String traceId = MDC.get(CommonConstants.TRACE_ID); //request head 加 traceId
        log.debug("feign get traceId:{}", traceId);
        if (StringUtils.isNotBlank(traceId)){
            template.header(CommonConstants.EXPAND_TRACE_ID, traceId);
        }
    }

}
